/**
 * NativeDynamicPay.java 
 * Copyright © 2015-3015, 杭州泊享网络科技有限公司
 * 
 * @author Liu Tao
 * @create 2015年3月10日
 */
package com.pshare.wx.service;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.jdom.JDOMException;
import org.springframework.stereotype.Service;

import com.pshare.constant.SeaxConstants;
import com.pshare.service.PayCallback;
import com.pshare.wx.bean.PrepayOrder;
import com.pshare.wx.tool.CommonUtil;
import com.pshare.wx.tool.ConfigUtil;
import com.pshare.wx.tool.MD5Util;
import com.pshare.wx.tool.PayCommonUtil;
import com.pshare.wx.tool.XMLUtil;
import com.tenpay.ResponseHandler;
import com.tenpay.util.WXUtil;

/**
 * 微信支付接口 微信后台接收到请求后调用本服务器接口进行业务逻辑处理
 */
@Service
public class WxPayService {
	
	private static final Logger logger = Logger.getLogger(WxPayService.class);

	/**
	 * 预支付
	 * @param orderNumber 业务系统订单号
	 * @param productId 业务系统商品号
	 * @param productPrice 价格
	 * @param productDesc 商品/订单描述
	 * @param remoteIp 下单IP
	 * @return PrepayOrder
	 */
	public PrepayOrder prepay(String orderNumber, String productId, String productPrice, String productDesc, String remoteIp) {
		String nonceStr = WXUtil.getNonceStr();
		SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
		parameters.put("appid", ConfigUtil.APP_ID);
		parameters.put("mch_id", ConfigUtil.MCH_ID);
		parameters.put("nonce_str", nonceStr);
		parameters.put("body", productDesc);
		parameters.put("out_trade_no", orderNumber);
		parameters.put("total_fee", productPrice);
		parameters.put("spbill_create_ip", remoteIp);
		parameters.put("notify_url", ConfigUtil.NOTIFY_URL);// 支付成功后回调的action，与JSAPI相同
		parameters.put("trade_type", "APP");
		parameters.put("product_id", productId);// 商品号要唯一
		String sign = PayCommonUtil.createSign(SeaxConstants.UTF8, parameters);
		parameters.put("sign", sign);
		String requestXML = PayCommonUtil.getRequestXml(parameters);
		String result = CommonUtil.httpsRequest(ConfigUtil.UNIFIED_ORDER_URL, "POST", requestXML);
		System.out.println(result);

		String prepay_id = null;
		try {
			Map<String, String> map = XMLUtil.doXMLParse(result);
			String returnCode = map.get("return_code");
			String resultCode = map.get("result_code");
			if (returnCode.equalsIgnoreCase(SeaxConstants.SUCCESS) && resultCode.equalsIgnoreCase(SeaxConstants.SUCCESS)) {
				prepay_id = map.get("prepay_id");
			}
		} catch (JDOMException | IOException e) {
			e.printStackTrace();
		}

		PrepayOrder prepayOrder = genPrepayOrder(prepay_id, nonceStr);
		return prepayOrder;
	}
	
	private PrepayOrder genPrepayOrder(String prepayId, String nonceStr) {
		long timestamp = WXUtil.getTimeStamp();
		SortedMap<Object, Object> params = new TreeMap<Object, Object>();
		params.put("appid", ConfigUtil.APP_ID);
		params.put("noncestr", nonceStr);
		params.put("package", "Sign=WXPay");
		params.put("partnerid", ConfigUtil.MCH_ID);
		params.put("prepayid", prepayId);
		params.put("timestamp", timestamp + "");
		String sign = PayCommonUtil.createSign(SeaxConstants.UTF8, params);

		PrepayOrder prepayOrder = new PrepayOrder();
		prepayOrder.setPrepayid(prepayId);
		prepayOrder.setPartnerid(ConfigUtil.MCH_ID);
		prepayOrder.setAppid(ConfigUtil.APP_ID);
		prepayOrder.setNoncestr(nonceStr);
		prepayOrder.setPackageValue("Sign=WXPay");
		prepayOrder.setTimestamp(timestamp);
		 prepayOrder.setSign(sign);
		return prepayOrder;
	}
	
	/**
	 * 付款完成的通知处理
	 * 
	 * @param request
	 * @param response
	 * @param callback
	 * @throws Exception
	 */
	public void handleNotify(HttpServletRequest request, HttpServletResponse response, PayCallback callback) throws Exception {
		// 创建支付应答对象
		ResponseHandler resHandler = new ResponseHandler(request, response);

		String return_code = resHandler.getParameter("return_code");
		if (!"SUCCESS".equals(return_code)) {
			logger.warn("支付失败，错误信息：" + return_code + "----" + resHandler.getParameter("return_msg"));
			return;
		}
		
		String sign = resHandler.getParameter("sign");  // 签名
		resHandler.removeParameter("sign");
		String calculatedSign = PayCommonUtil.createSign(SeaxConstants.UTF8, resHandler.getAllParameters());
		if (!calculatedSign.equals(sign)) {
			logger.warn("支付失败，签名错误：" + sign + " ---- " + calculatedSign);
			return;
		}
		
		String total_fee = resHandler.getParameter("total_fee");
		String out_trade_no = resHandler.getParameter("out_trade_no");
		logger.info("微信回调获取产品号====out_trade_no===:"+out_trade_no);
		String transaction_id = resHandler.getParameter("transaction_id");

		// ------------------------------
		// 处理业务开始
		// ------------------------------

		// 处理数据库逻辑
		// 注意交易单不要重复处理
		// 注意判断返回金额
		callback.doWork(out_trade_no, transaction_id, total_fee, null,PayCallback.TYPE_WX);

		// ------------------------------
		// 处理业务完毕
		// ------------------------------
		resHandler.sendToCFT(PayCommonUtil.setXML(SeaxConstants.SUCCESS, "OK"));
	}
	
	/**
	 * 交易订单查询
	 * 
	 * @param orderNum 业务系统订单号
	 * @param payCode 支付系统订单号
	 * @return String
	 */
	public String queryTrans(String orderNumber, String payCode) throws Exception {
		if (StringUtils.isBlank(payCode) && StringUtils.isBlank(orderNumber)) {
			logger.error("payCode and orderNumber are all blank");
			return null;
		}
		
		SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
		parameters.put("appid", ConfigUtil.APP_ID);
		parameters.put("mch_id", ConfigUtil.MCH_ID);
		parameters.put("transaction_id", payCode);
		parameters.put("out_trade_no", orderNumber);
		parameters.put("nonce_str", WXUtil.getNonceStr());
		String sign = PayCommonUtil.createSign(SeaxConstants.UTF8, parameters);
		parameters.put("sign", sign);
		String requestXML = PayCommonUtil.getRequestXml(parameters);
		
		String result = CommonUtil.httpsRequest(ConfigUtil.CHECK_ORDER_URL, "POST", requestXML);
		System.out.println(result);

		String trade_state = null;
		try {
			Map<String, String> map = XMLUtil.doXMLParse(result);
			String returnCode = map.get("return_code");
			String resultCode = map.get("return_msg");
			if (returnCode.equalsIgnoreCase(SeaxConstants.SUCCESS) && resultCode.equalsIgnoreCase(SeaxConstants.SUCCESS)) {
				trade_state = map.get("trade_state");
				logger.error(trade_state);
			} else {
				logger.error("-------------duang-----------");
			}
		} catch (JDOMException | IOException e) {
			e.printStackTrace();
		}
		
		return trade_state;
	}
	
	public static String createSign(String characterEncoding, SortedMap<Object,Object> parameters){
		StringBuffer sb = new StringBuffer();
		Set es = parameters.entrySet();
		Iterator it = es.iterator();
		while(it.hasNext()) {
			Map.Entry entry = (Map.Entry)it.next();
			String k = (String)entry.getKey();
			Object v = entry.getValue();
			if(null != v && !"".equals(v) 
					&& !"token".equalsIgnoreCase(k) && !"sign".equalsIgnoreCase(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + "d930ea5d");
		String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
		return sign;
	}

}
